using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;
using JGSY.CMS.LowCode.Platform.Infrastructure.Configuration;
using JGSY.CMS.LowCode.Platform.Infrastructure.Configuration.Models;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;

// 为了避免类型名冲突，使用别名
using DomainRouteMapping = JGSY.CMS.LowCode.Platform.Domain.Entities.PermissionRouteMapping;
using ConfigRouteMapping = JGSY.CMS.LowCode.Platform.Infrastructure.Configuration.Models.PermissionRouteMapping;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 权限路由映射服务实现
    /// 提供集中管理、热更新和高效解析功能
    /// </summary>
    public class PermissionRouteMappingService : IPermissionRouteMappingService
    {
        private readonly IPermissionRouteMappingRepository _repository;
        private readonly IMemoryCache _cache;
        private readonly ILogger<PermissionRouteMappingService> _logger;
        private readonly EnhancedConfigurationMappingFactory? _configFactory;
        
        private static readonly string CacheKey = "permission_route_mappings";
        private readonly MemoryCacheEntryOptions _cacheOptions;

        public PermissionRouteMappingService(
            IPermissionRouteMappingRepository repository,
            IMemoryCache cache,
            ILogger<PermissionRouteMappingService> logger,
            EnhancedConfigurationMappingFactory? configFactory = null)
        {
            _repository = repository;
            _cache = cache;
            _logger = logger;
            _configFactory = configFactory;
            _cacheOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
                SlidingExpiration = TimeSpan.FromMinutes(15)
            };
        }

        public async Task<IEnumerable<PermissionRouteMappingDto>> GetActiveAsync()
        {
            var entities = await _repository.GetActiveAsync();
            return entities.Select(MapToDto);
        }

        public async Task<(List<PermissionRouteMappingDto> items, int total)> GetPagedAsync(
            int pageIndex = 1, int pageSize = 20, string? group = null, bool? isActive = null, string? search = null)
        {
            // 简化实现，实际应在仓储层支持分页
            var allMappings = await _repository.GetAllAsync();
            
            var query = allMappings.AsQueryable();
            
            if (!string.IsNullOrEmpty(group))
                query = query.Where(m => m.Group == group);
                
            if (isActive.HasValue)
                query = query.Where(m => m.IsActive == isActive.Value);
                
            if (!string.IsNullOrEmpty(search))
            {
                query = query.Where(m => 
                    m.Path.Contains(search, StringComparison.OrdinalIgnoreCase) ||
                    m.PermissionCode.Contains(search, StringComparison.OrdinalIgnoreCase) ||
                    (m.Name != null && m.Name.Contains(search, StringComparison.OrdinalIgnoreCase)));
            }
            
            var total = query.Count();
            var items = query
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .Select(MapToDto)
                .ToList();
                
            return (items, total);
        }

        public async Task<PermissionRouteMappingDto?> GetByIdAsync(long id)
        {
            var entity = await _repository.GetByIdAsync(id);
            return entity != null ? MapToDto(entity) : null;
        }

        public async Task<long> CreateAsync(PermissionRouteMappingDto dto)
        {
            var entity = MapToEntity(dto);
            entity.CreatedAt = DateTime.UtcNow;
            entity.UpdatedAt = DateTime.UtcNow;
            
            var id = await _repository.AddAsync(entity);
            await RefreshCacheAsync();
            
            return id;
        }

        public async Task UpdateAsync(long id, PermissionRouteMappingDto dto)
        {
            var entity = MapToEntity(dto);
            entity.Id = id;
            entity.UpdatedAt = DateTime.UtcNow;
            
            await _repository.UpdateAsync(entity);
            await RefreshCacheAsync();
        }

        public async Task DeleteAsync(long id)
        {
            await _repository.DeleteAsync(id);
            await RefreshCacheAsync();
        }

        public async Task BatchDeleteAsync(IEnumerable<long> ids)
        {
            await _repository.BatchDeleteAsync(ids);
            await RefreshCacheAsync();
        }

        public async Task<string?> ResolvePermissionAsync(string path, string method)
        {
            var cached = await GetCachedMappingsAsync();
            
            foreach (var mapping in cached.Where(m => m.IsActive).OrderBy(m => m.Priority))
            {
                if (IsMatch(path, mapping.Path) && 
                    string.Equals(mapping.Method, method, StringComparison.OrdinalIgnoreCase))
                {
                    return mapping.PermissionCode;
                }
            }
            
            return null;
        }

        public async Task<Dictionary<string, string>> BatchResolvePermissionsAsync(
            IEnumerable<(string path, string method)> requests)
        {
            var result = new Dictionary<string, string>();
            var cached = await GetCachedMappingsAsync();
            var activeMappings = cached.Where(m => m.IsActive).OrderBy(m => m.Priority).ToList();
            
            foreach (var (path, method) in requests)
            {
                var key = $"{method}:{path}";
                
                var matching = activeMappings.FirstOrDefault(m => 
                    IsMatch(path, m.Path) && 
                    string.Equals(m.Method, method, StringComparison.OrdinalIgnoreCase));
                    
                if (matching != null)
                {
                    result[key] = matching.PermissionCode;
                }
            }
            
            return result;
        }

        public async Task<IEnumerable<string>> GetGroupsAsync()
        {
            return await _repository.GetGroupsAsync();
        }

        public bool ValidatePathPattern(string pattern)
        {
            try
            {
                // 基本验证：检查是否是有效的路径模式
                if (string.IsNullOrWhiteSpace(pattern))
                    return false;
                    
                if (!pattern.StartsWith("/"))
                    return false;
                    
                // 转换为正则表达式测试
                var regex = Regex.Escape(pattern)
                    .Replace("\\*\\*", ".*")
                    .Replace("\\*", "[^/]+");
                    
                _ = new Regex(regex, RegexOptions.IgnoreCase);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public async Task<bool> HasConflictAsync(string path, string method, long? excludeId = null)
        {
            return await _repository.HasConflictAsync(path, method, excludeId);
        }

        public async Task<int> ImportFromConfigurationAsync(bool replaceExisting = false)
        {
            if (_configFactory == null)
            {
                _logger.LogWarning("Configuration factory not available for import");
                return 0;
            }
            
            var config = _configFactory.GetPermissionConfiguration();
            var configMappings = config?.RouteMappings ?? new List<ConfigRouteMapping>();
            
            var entities = new List<DomainRouteMapping>();
            
            foreach (var configMapping in configMappings)
            {
                foreach (var method in configMapping.Methods)
                {
                    entities.Add(new DomainRouteMapping
                    {
                        Path = configMapping.Path,
                        Method = method.Key,
                        PermissionCode = method.Value,
                        Name = $"Config: {configMapping.Path} {method.Key}",
                        Description = "Imported from configuration",
                        Priority = 100, // 配置来源优先级较低
                        IsActive = true,
                        Source = "Configuration",
                        Group = "Config",
                        CreatedAt = DateTime.UtcNow,
                        UpdatedAt = DateTime.UtcNow
                    });
                }
            }
            
            var imported = await _repository.BatchImportAsync(entities, replaceExisting);
            
            if (imported > 0)
            {
                await RefreshCacheAsync();
            }
            
            return imported;
        }

        public async Task<string> ExportAsJsonAsync(string? group = null)
        {
            return await _repository.ExportAsJsonAsync(group);
        }

        public async Task<int> ImportFromJsonAsync(string json, bool replaceExisting = false)
        {
            try
            {
                var dtoList = JsonSerializer.Deserialize<List<PermissionRouteMappingDto>>(json);
                if (dtoList == null || !dtoList.Any())
                    return 0;
                
                var entities = dtoList.Select(dto => MapToEntity(dto)).ToList();
                var imported = await _repository.BatchImportAsync(entities, replaceExisting);
                
                if (imported > 0)
                {
                    await RefreshCacheAsync();
                }
                
                return imported;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to import mappings from JSON");
                throw;
            }
        }

        public async Task<PermissionRouteMappingStatisticsDto> GetStatisticsAsync()
        {
            var (total, active, groups) = await _repository.GetStatisticsAsync();
            
            return new PermissionRouteMappingStatisticsDto
            {
                TotalMappings = total,
                ActiveMappings = active,
                GroupCount = groups,
                LastUpdated = DateTime.UtcNow
            };
        }

        public async Task RefreshCacheAsync()
        {
            _cache.Remove(CacheKey);
            await GetCachedMappingsAsync(); // 重新加载缓存
            _logger.LogInformation("Permission route mapping cache refreshed");
        }

        public async Task<IEnumerable<PermissionRouteMappingDto>> TestMatchAsync(string path, string method)
        {
            var cached = await GetCachedMappingsAsync();
            var matches = new List<DomainRouteMapping>();
            
            foreach (var mapping in cached.Where(m => m.IsActive))
            {
                if (IsMatch(path, mapping.Path) && 
                    string.Equals(mapping.Method, method, StringComparison.OrdinalIgnoreCase))
                {
                    matches.Add(mapping);
                }
            }
            
            return matches.OrderBy(m => m.Priority).Select(MapToDto);
        }

        private async Task<List<DomainRouteMapping>> GetCachedMappingsAsync()
        {
            if (_cache.TryGetValue(CacheKey, out List<DomainRouteMapping>? cached) && cached != null)
            {
                return cached;
            }
            
            var mappings = (await _repository.GetActiveAsync()).ToList();
            _cache.Set(CacheKey, mappings, _cacheOptions);
            
            return mappings;
        }

        private bool IsMatch(string requestPath, string pattern)
        {
            try
            {
                string regex = Regex.Escape(pattern)
                    .Replace("\\*\\*", ".*")
                    .Replace("\\*", "[^/]+");
                    
                if (!regex.StartsWith("^")) regex = "^" + regex;
                if (!regex.EndsWith("$")) regex += "$";
                
                return Regex.IsMatch(requestPath, regex, RegexOptions.IgnoreCase);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Invalid pattern: {Pattern}", pattern);
                return false;
            }
        }

        private PermissionRouteMappingDto MapToDto(DomainRouteMapping entity)
        {
            return new PermissionRouteMappingDto
            {
                Id = entity.Id,
                Path = entity.Path,
                Method = entity.Method,
                PermissionCode = entity.PermissionCode,
                Name = entity.Name,
                Description = entity.Description,
                Priority = entity.Priority,
                IsActive = entity.IsActive,
                Source = entity.Source,
                Group = entity.Group,
                SortOrder = entity.SortOrder,
                Remark = entity.Remark,
                CreatedBy = entity.CreatedBy,
                UpdatedBy = entity.UpdatedBy,
                CreatedAt = entity.CreatedAt,
                UpdatedAt = entity.UpdatedAt,
                ExtendedProperties = entity.ExtendedProperties
            };
        }

        private DomainRouteMapping MapToEntity(PermissionRouteMappingDto dto)
        {
            return new DomainRouteMapping
            {
                Id = dto.Id,
                Path = dto.Path,
                Method = dto.Method,
                PermissionCode = dto.PermissionCode,
                Name = dto.Name,
                Description = dto.Description,
                Priority = dto.Priority,
                IsActive = dto.IsActive,
                Source = dto.Source,
                Group = dto.Group,
                SortOrder = dto.SortOrder,
                Remark = dto.Remark,
                CreatedBy = dto.CreatedBy,
                UpdatedBy = dto.UpdatedBy,
                CreatedAt = dto.CreatedAt,
                UpdatedAt = dto.UpdatedAt,
                ExtendedProperties = dto.ExtendedProperties
            };
        }
    }
}
